﻿//===============================================================================
// Microsoft Innovation Centre - Western Europe
// Copyright (c) 2008 Microsoft Corporation. All rights reserved.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious.  No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
//===============================================================================

using System;
using System.IO;
using System.Net;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Resources;

namespace Microsoft.WVB.Framework.AdControls
{
    /// <summary>
    /// An <see cref="AdBase"/> derived control intended to display Xaml/Xap Ads.
    /// </summary>
    /// <remarks>When Templating this control, you will need to modify the AdXap.xaml file.
    /// This control has 2 controls part of its Template.
    /// A <see cref="Button"/> control named <b>CloseButton</b> used for Closing the Ad if allowed.
    /// A <see cref="ContentControl"/> control named <b>MediaContent</b> asa placeholder for the Silverlight UserControl to load.
    /// </remarks>
    [TemplatePart(Name = AdXap.CloseButtonName, Type = typeof(Button)),
    TemplatePart(Name = AdXap.MediaContentName, Type = typeof(ContentControl))]
    public class AdXap : AdBase, IDisposable
    {
        private const string CloseButtonName = "CloseButton";
        private const string MediaContentName = "MediaContent";
        private const string InstanceName = "Instance";

        private OpenReadCompletedEventHandler openReadHandler = null;
        private WebClient webclient = null;
        private Assembly pkgAssembly = null;
        private MouseButtonEventHandler adClickHandler = null;
        private RoutedEventHandler closeHandler = null;
        private UserControl adUserControl = null;

        internal Button CloseButton = null;
        internal ContentControl Media = null;

        /// <summary>
        /// Public <see cref="AdXap"/> constructor. Initialize a <see cref="AdXap"/> object.
        /// </summary>
        public AdXap()
            : base()
        {
            this.DefaultStyleKey = typeof(AdXap);

            webclient = new WebClient();
        }

        /// <summary>
        /// Overriden. Acquire control part of the Template Contract.
        /// AdXap has a <see cref="ContentControl"/> and a <see cref="Button"/> control in its contract.
        /// </summary>
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            this.Media = base.GetTemplateChild(AdXap.MediaContentName) as ContentControl;
            this.CloseButton = base.GetTemplateChild(AdXap.CloseButtonName) as Button;

            if (this.Media != null)
            {
                if (this.CloseButton != null)
                {
                    if (closeHandler == null)
                    {
                        closeHandler = delegate(object sender, RoutedEventArgs e)
                        {
                            this.OnAdStopped(this, new EventArgs());
                        };
                    }
                    this.CloseButton.Click += closeHandler;
                }
            }
        }

        /// <summary>
        /// Overriden. Execute appropriate actions if the user stops the Ad execution.
        /// </summary>
        /// <param name="sender">The <see cref="Object"/> on which the Ad has been stopped.</param>
        /// <param name="e">The <see cref="EventArgs"/> object.</param>
        protected override void OnAdStopped(object sender, EventArgs e)
        {
            adUserControl = null;
            base.OnAdStopped(sender, e);
        }

        /// <summary>
        /// Overriden. Execute appropriate actions when notified by the End of the Annimation.
        /// </summary>
        /// <param name="sender">The <see cref="Object"/> on which the Ad has ended.</param>
        /// <param name="e">The <see cref="EventArgs"/> object.</param>
        protected override void OnAdEnded(object sender, EventArgs e)
        {
            adUserControl = null;
            base.OnAdEnded(sender, e);
        }

        /// <summary>
        /// Overriden. Buffers the Animation and load it into a control before being displayed.
        /// </summary>
        /// <param name="adContext">the <see cref="AdContext"/> describing the Ad.</param>
        public override void Buffer(AdContext adContext)
        {
            if (this.CloseButton != null)
            {
                this.CloseButton.IsEnabled = adContext.CanSkip;
            }

            if (openReadHandler == null)
            {
                openReadHandler = delegate(object sender, OpenReadCompletedEventArgs e)
                {
                    Stream package = e.Result;
                    pkgAssembly = LoadAssembliesFromXap(package);
                    webclient.OpenReadCompleted -= openReadHandler;
                };
                webclient.OpenReadCompleted += openReadHandler;
            }

            webclient.OpenReadAsync(adContext.Source);

            if (adClickHandler == null)
            {
                adClickHandler = delegate(object sender, MouseButtonEventArgs e)
                {
                    System.Windows.Browser.HtmlPage.Window.Navigate(adContext.Click, "_blank");
                };
            }
            Media.MouseLeftButtonUp += adClickHandler;

            string controlFullName = exctractControlFullName(adContext.Source);

            if (controlFullName != String.Empty)
                adUserControl = pkgAssembly.CreateInstance(controlFullName) as UserControl;
        }

        private Assembly LoadAssembliesFromXap(Stream package)
        {
            // Get a stream containing the application manifest
            string appManifestString = new StreamReader(
                                    Application.GetResourceStream(new
                                    StreamResourceInfo(package, null),
                                    new Uri("AppManifest.xaml",
                                    UriKind.Relative)).Stream)
                                    .ReadToEnd();

            // Read the manifest
            Assembly mainAssembly = null;
            Deployment deployment = (Deployment)XamlReader.Load(appManifestString);

            // Grab each assembly and load it
            foreach (AssemblyPart assemblyPart in deployment.Parts)
            {
                string source = assemblyPart.Source;
                StreamResourceInfo streamInfo =
                                Application.GetResourceStream(
                                new StreamResourceInfo(package,
                                        "application/binary"),
                                new Uri(source, UriKind.Relative));

                // Load individual assembly
                Assembly assembly = assemblyPart.Load(streamInfo.Stream);

                // Get the main application assembly
                if (assembly.FullName.Split(',')[0] ==
                                        deployment.EntryPointAssembly)
                {
                    mainAssembly = assembly;
                }
            }
            return mainAssembly;
        }

        /// <summary>
        /// Overriden. Execute the operation that starts the Ad display.
        /// </summary>
        public override void Start()
        {
           if ((Media != null) && (adUserControl != null))
           {
               Media.Content = adUserControl;
           }
        }

        private string exctractControlFullName(Uri packageRequestUri)
        {
            string instanceName = string.Empty;
       
            string[] nameValue = packageRequestUri.Query.Split(new string[] { "&" }, StringSplitOptions.RemoveEmptyEntries);
            if (nameValue.Length > 0)
            {
                for (int i = 0; i < nameValue.Length; i++)
                {
                    string[] s = nameValue[i].Split(new string[] { "=" }, StringSplitOptions.RemoveEmptyEntries);
                    if (s.Length == 2)
                    {
                        if (s[0].Equals(AdXap.InstanceName, StringComparison.InvariantCultureIgnoreCase))
                        {
                            instanceName = s[0];
                            break;
                        }
                    }
                }
            }

            return instanceName;
        }

        #region IDisposable Members

        public void Dispose()
        {
            if (webclient != null)
            {
                webclient.OpenReadCompleted -= openReadHandler;
            }

            if (Media != null)
            {
                Media.MouseLeftButtonUp -= adClickHandler;
            }

            if (CloseButton != null)
            {
                CloseButton.Click -= closeHandler;
            }
        }

        #endregion
    }
}
